<template>
	<scroll-view
		class="tui-scroll__view"
		:class="[isFixed && !isSticky ? 'tui-tabs__fixed' : '', isSticky ? 'tui-tabs__sticky' : '']"
		:style="{ height: height + 'rpx', background: backgroundColor, top: isFixed || isSticky ? top + 'px' : 'auto', zIndex: isFixed || isSticky ? zIndex : 'auto' }"
		:scroll-x="scrolling"
		:scroll-with-animation="scrolling"
		:scroll-left="scrollLeft"
	>
		<view class="tui-tabs__wrap">
			<view class="tui-tabs__list" :class="[scroll ? 'tui-tabs__scroll' : '']" :style="{ height: height + 'rpx' }">
				<view class="tui-tabs__item" :style="{ height: height + 'rpx' }" v-for="(item, index) in tabs" :key="index" @tap="handleClick" :data-index="index">
					<view
						class="tui-item__child"
						:style="{
							color: currentTab == index ? selectedColor : color,
							fontSize: size + 'rpx',
							lineHeight: size + 'rpx',
							fontWeight: bold && currentTab == index ? 'bold' : 'normal'
						}"
					>
						<text>{{ item }}</text>
					</view>
				</view>

				<view
					class="tui-tabs__line"
					:class="[needTransition ? 'tui-transition' : '']"
					:style="{
						backgroundColor: sliderBgColor,
						height: sliderHeight,
						borderRadius: sliderRadius,
						bottom: bottom,
						width: lineWidth + 'px',
						transform: `translateX(${translateX}px)`
					}"
				></view>
			</view>
		</view>
	</scroll-view>
</template>

<script setup>
import { ref, reactive, toRefs, watch, getCurrentInstance, onBeforeMount, onMounted } from 'vue'

const { ctx } = getCurrentInstance()

const emit = defineEmits(['change'])

const props = defineProps({
	// 标签页数据源
	tabs: {
		type: Array,
		default() {
			return []
		}
	},
	// 当前选项卡
	current: {
		type: Number,
		default: 0
	},
	// 是否可以滚动
	scroll: {
		type: Boolean,
		default: false
	},
	// tab高度 rpx
	height: {
		type: [Number, String],
		default: 80
	},
	//组件左侧距离屏幕的间隙 单位rpx
	leftGap: {
		type: [Number, String],
		default: 0
	},
	backgroundColor: {
		type: String,
		default: '#fff'
	},
	//字体大小
	size: {
		type: Number,
		default: 28
	},
	//字体颜色
	color: {
		type: String,
		default: '#666'
	},
	//选中后字体颜色
	selectedColor: {
		type: String,
		default: '#5677fc'
	},
	//选中后 是否加粗 ，未选中则无效
	bold: {
		type: Boolean,
		default: false
	},
	//滑块高度
	sliderHeight: {
		type: String,
		default: '5px'
	},
	//滑块背景颜色
	sliderBgColor: {
		type: String,
		default: '#5677fc'
	},
	//滑块 radius
	sliderRadius: {
		type: String,
		default: '5px'
	},
	//滑块bottom
	bottom: {
		type: String,
		default: '0'
	},
	//是否固定
	isFixed: {
		type: Boolean,
		default: false
	},
	//吸顶效果，为true时isFixed失效
	isSticky: {
		type: Boolean,
		default: false
	},
	//isFixed=true时，tab top值 px
	top: {
		type: Number,
		// #ifndef H5
		default: 0,
		// #endif

		// #ifdef H5
		default: 44
		// #endif
	},
	zIndex: {
		type: [Number, String],
		default: 996
	}
})

const state = reactive({
	/* 未渲染数据 */
	windowWidth: 0, // 屏幕宽度
	tabItems: [], // 所有 tab 节点信息

	/* 渲染数据 */
	scrolling: true, // 控制 scroll-view 滚动以在异步加载数据的时候能正确获得 dom 信息
	needTransition: false, // 下划线是否需要过渡动画
	translateX: 0, // 下划 line 的左边距离
	lineWidth: 0, // 下划 line 宽度
	scrollLeft: 0, // scroll-view 左边滚动距离
	currentTab: 0,
	gap: -1
})

/**
 * 监听数据变化, 如果改变重新初始化参数
 */
watch(
	() => props.tabs,
	nVal => {
		state.scrolling = false
		// 异步加载数据时候, 延迟执行 init 方法, 防止无法正确获取 dom 信息
		setTimeout(() => init(), 200)
	}
)

/**
 *  监听 currentTab 变化, 做对应处理
 */
watch(
	() => props.current,
	nVal => {
		scrollByIndex(nVal)
	}
)

watch(
	() => props.leftGap,
	nVal => {
		state.gap = uni.upx2px(Number(nVal))
	}
)

onBeforeMount(() => {
	state.currentTab = props.current
})

onMounted(() => {
	state.gap = uni.upx2px(Number(props.leftGap))
	init()
})

/**
 *  初始化函数
 */
const init = () => {
	const { windowWidth } = uni.getSystemInfoSync()

	const query = uni
		.createSelectorQuery()
		// #ifndef MP-ALIPAY
		.in(ctx)
	// #endif

	query
		.select('.tui-scroll__view')
		.boundingClientRect(res => {
			if (res) {
				state.windowWidth = res.width || windowWidth
			}
		})
		.exec()

	query
		.selectAll('.tui-item__child')
		.boundingClientRect(res => {
			state.scrolling = true
			state.tabItems = [...res]
			scrollByIndex(state.currentTab, false)
		})
		.exec()
}

/**
 * 切换菜单
 */
const handleClick = e => {
	const index = Number(e.currentTarget.dataset.index)
	emit('change', {
		index: index
	})
	scrollByIndex(index)
}

/**
 * 滑动到指定位置
 * @param tabCur: 当前激活的tabItem的索引
 * @param needTransition: 下划线是否需要过渡动画, 第一次进来应设置为false
 */
const scrollByIndex = (tabCur, needTransition = true) => {
	let item = state.tabItems[tabCur]
	if (!item) return
	let itemWidth = item.width || 0,
		itemLeft = item.left || 0
	state.needTransition = needTransition
	state.currentTab = tabCur

	// 超出滚动的情况
	if (props.scroll) {
		// 保持滚动后当前 item '尽可能' 在屏幕中间
		let scrollLeft = itemLeft - (state.windowWidth - itemWidth) / 2
		state.scrollLeft = scrollLeft
		state.translateX = itemLeft - state.gap
		state.lineWidth = itemWidth
	} else {
		// 不超出滚动的情况
		state.translateX = itemLeft - state.gap
		state.lineWidth = itemWidth
	}
}

const { scrolling, needTransition, translateX, lineWidth, scrollLeft, currentTab, gap } = toRefs(state)
</script>

<style lang="scss" scoped>
.tui-scroll__view {
	width: 100%;
	height: 80rpx;
	overflow: hidden;
}

.tui-tabs__fixed {
	position: fixed;
	left: 0;
}

.tui-tabs__sticky {
	position: sticky;
	left: 0;
}

.tui-tabs__wrap {
	padding-bottom: 20rpx;
}

.tui-tabs__list {
	position: relative;
	height: 80rpx;
	display: flex;
}

.tui-tabs__scroll {
	white-space: nowrap !important;
	display: block !important;
}

.tui-tabs__scroll .tui-tabs__item {
	padding: 0 30rpx;
	display: inline-flex;
}

.tui-tabs__scroll .tui-item__child {
	display: block !important;
}

.tui-tabs__item {
	flex: 1;
	text-align: center;
	padding: 0 10rpx;
	box-sizing: border-box;
	transition: color 0.3s ease-in-out;
	display: flex;
	align-items: center;
	justify-content: center;
	position: relative;
	z-index: 2;
}

.tui-item__child {
	display: inline-block;
}

.tui-tabs__line {
	position: absolute;
	left: 0;
	width: 0;
	display: inline-block;
	z-index: 1;
	background-color: #5677fc;
	background-image: repeating-linear-gradient(45deg, hsla(0, 0%, 100%, 0.2), transparent 25%);
}

.tui-tabs__line.tui-transition {
	transition: width 0.3s, transform 0.3s;
}
</style>
